package zdream.pmfield.test.stage.effect;

import org.junit.Before;
import org.junit.Test;

import zdream.pmfield.data.foe.Foe;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.data.foe.VStat;
import zdream.pmfield.stage.StageBuilderForTest;
import zdream.pmfield.stage.StageWrapper;
import zdream.pmfield.stage.action.AttackReport;
import zdream.pmfield.stage.action.BuffAction;
import zdream.pmfield.stage.message.ActionRequestMessage;
import zdream.pmfield.stage.message.ActionStartMessage;
import zdream.pmfield.stage.message.AttackMessage;
import zdream.pmfield.stage.message.FoeAddBuffMessage;
import zdream.pmfield.stage.message.FoeReceiveDamageMessage;
import zdream.pmfield.stage.message.FoeRemoveBuffMessage;
import zdream.pmfield.stage.message.RollReportMessage;
import zdream.pmfield.stage.message.TurnStartMessage;
import zdream.pmfield.stage.object.FoeActor;
import zdream.pmfield.storage.FoeTemplateStorage;
import zdream.pmfield.test.utils.ResourceConstant;
import zdream.pmfield.test.utils.StageConstant;

import static org.junit.Assert.*;

/**
 * @author Zdream
 * @date 2023-12-11
 * @since 0.0.1
 */
public class ConfusedBuffCase {
	FoeTemplateStorage storage;

	@Before
	public void before() {
		storage = new FoeTemplateStorage();
		storage.load();
		storage.loadMovesInResource(ResourceConstant.RES_PATH_TEST_MOVES_JSON);
	}

	@Test
	public void testConfusedEffect() {
		MoveTemplate confusedMove = storage.findMoveById(10000029, 1);
		assertEquals("肯定混乱", confusedMove.name);
		MoveTemplate normalMove = storage.findMoveById(10000020, 2);
		assertEquals("物理的", normalMove.name);
		assertEquals(0, normalMove.checkRateFixed);

		Foe foe1 = Foe.builder(storage.findFoeById(4))
				.withLevel(30)
				.withMove(confusedMove)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(1))
				.withLevel(30)
				.withMove(normalMove)
				.build();

		final StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.disableDistanceCheck()
				.buildWrapper();

		System.out.println("TEST 1: apply confused");

		wrapper.printBeforeHandleMessage();
		wrapper.onDefaultActionRequest();
		wrapper.runUntil(TurnStartMessage.class, message -> message.foe.foe == foe1);

		wrapper.clearOnMessageHooks();
		wrapper.onActionRequestForAll(wrapper.createDefaultController().withActionChecker(action -> {
			assertEquals(foe1, action.foe.foe);
			assertEquals(confusedMove, action.move.move);
		}));
		wrapper.runUntil(FoeAddBuffMessage.class, message -> {
			assertEquals(foe2, message.foe.foe);
			assertTrue(message.buff.is(StageConstant.EFFECT_CONFUSED));
			assertTrue(message.success);
			return true;
		});

		System.out.println("TEST 2: 在混乱状态下, 攻击时骰子属性会变, 非攻击时不会变");
		wrapper.clearOnMessageHooks();
		wrapper.onDefaultActionRequest();
		wrapper.runUntil(TurnStartMessage.class, message -> message.foe.foe == foe2);

		wrapper.runUntil(RollReportMessage.class, message -> {
			assertEquals(StageConstant.ROLL_TITLE_MOVE_POINT, message.title);
			assertEquals(2, message.rolls.length);
			assertEquals(VStat.FLEXIBILITY, message.rolls[0].vStat);
			assertEquals(VStat.FLEXIBILITY, message.rolls[1].vStat);
			return true;
		});
		wrapper.runUntil(ActionRequestMessage.class);
		wrapper.runUntil(RollReportMessage.class, message -> {
			assertEquals(StageConstant.ROLL_TITLE_ACTION, message.title);
			assertEquals(normalMove.vStats.length, message.rolls.length);
			assertEquals(VStat.STRENGTH, message.rolls[0].vStat);
			assertNotEquals(VStat.STRENGTH, message.rolls[1].vStat);
			assertEquals(VStat.STRENGTH, message.rolls[2].vStat);
			assertNotEquals(VStat.STRENGTH, message.rolls[3].vStat);
			return true;
		});

		System.out.println("TEST 3: 在混乱状态下, 大失败时攻击全 miss, 自己还受伤");
		wrapper.clearOnMessageHooks();
		wrapper.onDefaultActionRequest();
		wrapper.runUntil(TurnStartMessage.class, message -> message.foe.foe == foe2);
		wrapper.runUntil(ActionRequestMessage.class);

		wrapper.setNextRollCheckValue(101);
		wrapper.runUntil(RollReportMessage.class, message -> {
			assertEquals(StageConstant.ROLL_TITLE_ACTION, message.title);
			assertFalse(message.rolls[0].result);
			assertFalse(message.rolls[1].result);
			assertFalse(message.rolls[2].result);
			assertFalse(message.rolls[3].result);
			return true;
		});
		final FoeActor foe1Actor = wrapper.stage.findFoe(foe1);
		int shield = foe1Actor.currentShield;
		int hp = foe1Actor.foe.currentHp;

		wrapper.runUntil(AttackMessage.class, message -> {
			final AttackReport report = message.report;
			assertEquals(1, report.items.size());

			final AttackReport.AttackReportItem item = report.items.get(0);
			assertTrue(item.miss);
			assertEquals(0, item.damage);

			assertEquals(shield, item.shieldFrom);
			assertEquals(shield, item.shieldTo);
			assertEquals(shield, foe1Actor.currentShield);
			assertEquals(hp, item.hpFrom);
			assertEquals(hp, item.hpTo);
			assertEquals(hp, foe1.currentHp);

			return true;
		});
		wrapper.runUntil(ActionStartMessage.class, message -> {
			assertTrue(message.action.isForBuff());

			final BuffAction buffAction = message.action.asBuff();
			assertTrue(buffAction.buff.is(StageConstant.BUFF_CONFUSED));
			return true;
		});
		wrapper.runUntil(FoeReceiveDamageMessage.class, message -> {
			assertEquals(foe2, message.foe.foe);
			assertTrue(message.damage > 0);
			return true;
		});
		wrapper.clearNextRollCheckValue();

		System.out.println("TEST 4: 混乱状态会自动消失");
		wrapper.clearOnMessageHooks();
		wrapper.onDefaultActionRequest();
		wrapper.runUntil(FoeRemoveBuffMessage.class, message -> {
			assertEquals(message.foe.foe, foe2);
			assertTrue(message.buff.is(StageConstant.BUFF_CONFUSED));
			return true;
		});
	}
}
